#include <iostream>
#include <functional>
#include <string>
#include <unordered_map>
#include <memory>
#include "request.pb.h"
#include "include/muduo/net/TcpServer.h"
#include "include/muduo/net/EventLoop.h"
#include "protobuf/codec.h"
#include "protobuf/dispatcher.h"
#include "muduo/base/Logging.h"
using namespace std;
class Server
{
    typedef shared_ptr<mh::TranslateRequest> TranslateRequestPtr;
    typedef shared_ptr<mh::AddRequest> AddRequestPtr;

public:
    Server(int port = 8088)
        : _server(&_baseloop, muduo::net::InetAddress("0.0.0.0", port), "Server", muduo::net::TcpServer::kReusePort),
          _dispatcher(bind(&Server::onUnknownMessage, this, placeholders::_1, placeholders::_2, placeholders::_3)),
          _codec(bind(&ProtobufDispatcher::onProtobufMessage, &_dispatcher, placeholders::_1, placeholders::_2, placeholders::_3))
    {
        _dispatcher.registerMessageCallback<mh::TranslateRequest>(bind(&Server::onTranslate, this, placeholders::_1, placeholders::_2, placeholders::_3));
        _dispatcher.registerMessageCallback<mh::AddRequest>(bind(&Server::onAdd, this, placeholders::_1, placeholders::_2, placeholders::_3));
        _server.setConnectionCallback(bind(&Server::onConnection, this, placeholders::_1));
        _server.setMessageCallback(bind(&ProtobufCodec::onMessage, &_codec, placeholders::_1, placeholders::_2, placeholders::_3));
    }
    void start()
    {
        _server.start();
        _baseloop.loop();
    }

private:
    void onUnknownMessage(const muduo::net::TcpConnectionPtr &conn, const MessagePtr &message, muduo::Timestamp)
    {
        LOG_INFO << "onUnknownMessage: " << message->GetTypeName();
        conn->shutdown();
    }
    void onConnection(const muduo::net::TcpConnectionPtr &conn)
    {
        if (conn->connected() == true)
        {
            cout << "新链接已建立： " << conn.get() << endl;
        }
        else
        {
            cout << "链接已关闭" << endl;
        }
    }
    string translate(const string &msg)
    {
        static std::unordered_map<std::string, std::string>
            dict_map = {
                {"Hello", "你好"},
                {"你好", "Hello"},
                {"World", "世界"},
                {"世界", "World"},
            };
        auto it = dict_map.find(msg);
        if (it == dict_map.end())
        {
            return "UnKnow";
        }
        return it->second;
    }
    void onTranslate(const muduo::net::TcpConnectionPtr &conn, const TranslateRequestPtr &message, muduo::Timestamp)
    {
        string msg = message->msg();
        string ret = translate(msg);
        mh::TranslateResponse resp;
        resp.set_msg(ret);
        _codec.send(conn, resp);
    }
    void onAdd(const muduo::net::TcpConnectionPtr &conn, const AddRequestPtr &message, muduo::Timestamp)
    {
        int num1 = message->num1();
        int num2 = message->num2();
        int ret = num1 + num2;
        mh::AddResponse resp;
        resp.set_result(ret);
        _codec.send(conn, resp);
    }

private:
    muduo::net::EventLoop _baseloop;
    muduo::net::TcpServer _server;
    ProtobufDispatcher _dispatcher;
    ProtobufCodec _codec;
};
int main()
{
    Server server(8088);
    server.start();
    return 0;
}